﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using HCM_maps_website.Models;
using HCM_maps_website.Process.BLL;
using HCM_maps_website.Process.DAL;
using HCM_maps_website.Process;

namespace HCM_maps_website.Controllers
{
    public class HomeController : Controller
    {
        //
        // GET: /Home/
        int[] nPics = new int[] { 6, 4, 12, 9, 28, 19, 57, 39, 97, 75 };
        int[] sizeMaps = new int[] { 1536, 1024, 3072, 2304, 7168, 4864, 14592, 9984, 24832, 19200 };
        float[] rate = new float[] { 1, 1, 2, 2.25f, 4.667f, 4.75f, 9.5f, 9.75f, 16.1666666667f, 18.75f };
        float[] mapCoor = new float[] { 10.897031f, 106.578541f, 10.894079f, 106.58591f, 10.894965f, 106.587296f, 10.890814f, 106.586112f };
        float[] deltaCoor = new float[] { 0.0493095f, 0.0474955f, 0.02437575f, 0.02413f, 0.01220925f, 0.01194825f, 0.00613225f, 0.006016f };
        int[] centerXY = new int[] { 568, 670, 1083, 1282, 2139, 2585, 4331, 4994, 8712, 9948 };
        //float centerLat = 10.773615f; float centerLong = 106.689385f;
        float centerLat = 10.773635f; float centerLong = 106.689385f;
        //float tempLat = 10.776685f; float tempLong = 106.683699f;
        //float distanceLat = 0.00307f; float distanceLong = 0.005689f;
        float distanceLat = 0.00307f; float distanceLong = 0.005686f;
        int pwidth = 256; int pheight = 256;

        ServiceBLL serviceBL = new ServiceBLL();
        public ViewResult Index()
        {
            return View();
        }

        [HttpPost]
        public PartialViewResult Search(string keywords)
        {
            //IEnumerable<ServiceModel> services = serviceBL.FindServiceByKeyword(keywords);

            List<int> arrpos = new List<int>();

            for (int i = 1; i < keywords.Length-1; i++)
            {
                if (keywords[i] == '.' && (keywords[i - 1].ToString().ToLower() == "q" ||
                    (keywords[i - 1].ToString().ToLower() == "p" && (i < 2 || (i >= 2 && keywords[i - 2].ToString().ToLower() != "t")))))
                {
                    arrpos.Add(i);
                }
            }

            for (int i = arrpos.Count - 1; i >= 0; i--)
            {
                keywords = keywords.Remove(arrpos[i],1);
            }

            SearchResult lstresult = SearchBLL.Search(keywords);

            return PartialView("_ServiceInfo", new Tuple<IEnumerable<ServiceModel>, IEnumerable<PlaceModels>>(lstresult.Service, lstresult.Place));
        }

        [HttpPost]
        public ActionResult GetData(int zoom,int x,int y,int width,int height)
        {
            return Json(GetImageData(zoom, x, y, width, height));
        }

        private object[] GetImageData(int zoom, int x, int y, int width, int height)
        {
            int scol = -x / pwidth; //sizeMaps[(zoom - 1) * 2];
            int srow = -y / pheight; //sizeMaps[(zoom - 1) * 2 + 1];

            int nPic_x = width / pwidth + 1;
            int nPic_y = height / pheight + 1;

            List<string> lstname = new List<string>();

            for (int i = srow; i < nPic_y + srow; i++)
            {
                for (int j = scol; j < nPic_x + scol; j++)
                {
                    lstname.Add(i.ToString("00") + "_" + j.ToString("00"));
                }
            }
            return new object[] { lstname.ToArray(), scol * pwidth + x, srow * pheight + y };
        }

        [HttpPost]
        public ActionResult Zoom(int[] array)
        {
            int curzoom = array[0];
            int zoom = array[1];
            int x = array[2];
            int y = array[3];
            int zx = array[4];
            int zy = array[5];
            int width = array[6];
            int height = array[7];

            double rate = Math.Pow(2, zoom - curzoom);

            int newzx = (int)((-x + zx - centerXY[(curzoom - 1) * 2]) * rate) + centerXY[(zoom - 1) * 2];
            int newzy = (int)((-y + zy - centerXY[(curzoom - 1) * 2 + 1]) * rate) + centerXY[(zoom - 1) * 2 + 1];
            int newmapx = zx - newzx; int newmapy = zy - newzy;

            return Json(new object[] { newmapx, newmapy ,
                        centerXY[(zoom - 1) * 2],centerXY[(zoom - 1) * 2 +1],centerLat,centerLong,
                          //distanceLat/(float)(18*Math.Pow(2,zoom-1)),distanceLong/(float)(30*Math.Pow(2,zoom-1))});
                          distanceLat,distanceLong});
        }

        public ActionResult GetUri()
        {
            object[] ob = { "../MapData/images/M_", "../MapData/images/S_", ".png",
                           centerXY[0],centerXY[1],centerLat,centerLong,
                          distanceLat,distanceLong};
            return Json(ob,JsonRequestBehavior.AllowGet);
        }

        public ActionResult GetNumPic(int zoom)
        {
            return Json(new int[] { nPics[(zoom - 1) * 2], nPics[(zoom - 1) * 2 + 1] }, JsonRequestBehavior.AllowGet);
        }

        [HttpPost]
        public ActionResult GetPlaceAroundLongLat(float plat, float plong, int type, int r)
        {
            Coordinate coor = new Coordinate(plat,plong);

            ServiceModel service = SearchBLL.GetNearPlaceCoordinate(coor);

            if (service != null)
            {
                return PartialView("_ServiceInfo", GetPlaceAround(service.Coordinate, type, r));
            }
            else return PartialView("_ServiceInfo", null);
        }

        [HttpPost]
        public ActionResult FindDuong(float sLat,float sLong,float eLat,float eLong)
        {
            

            List<DirectionDTO> listpath = DirectionService.ShortestPaths(new Coordinate(sLat, sLong), new Coordinate(eLat, eLong));

            //List<GraphNodeInfoEx> lstdir = DirectionService.ShortestPath(new Coordinate(sLat, sLong), new Coordinate(eLat, eLong));

            /*List<List<double>> arrListP = new List<List<double>>();

            

            if (listpath != null)
            {
                foreach (DirectionDTO graph in listpath)
                {
                    List<double> arrPoints = new List<double>();

                    foreach (DirectionNode node in graph.Path)
                    {

                        arrPoints.Add(node.Location.Longitude);
                        arrPoints.Add(node.Location.Latitude);
                    }

                    arrListP.Add(arrPoints);
                }
            }*/

            //if (lstdir != null)
            //{
            //    foreach (GraphNodeInfoEx graph in lstdir)
            //    {
            //        arrPoints.Add(graph.Location.Longitude);
            //        arrPoints.Add(graph.Location.Latitude);
            //    }

            //}


            List<List<StreetDir>> arrListP = new List<List<StreetDir>>();



            if (listpath != null)
            {
                foreach (DirectionDTO graph in listpath)
                {
                    List<StreetDir> arrPoints = new List<StreetDir>();

                    double length = graph.getPathLength();

                    foreach (DirectionNode node in graph.Path)
                    {
                        StreetDir strd = new StreetDir()
                        {
                            Mlat = node.Location.Latitude,
                            Mlong = node.Location.Longitude,
                            NextStreet = node.NextStreet,
                            Direction = node.DirectionGuide,
                            Length = length.ToString("0.000")
                        };
                        arrPoints.Add(strd);
                    }

                    arrListP.Add(arrPoints);
                }
            }

            return Json(arrListP);
        }

        [HttpPost]
        public ActionResult GetPlaceAroundPoint(int zoom,int x,int y,int type,int r)
        {
            int deltax = x - centerXY[(zoom - 1) * 2];
            int deltay = y - centerXY[(zoom - 1) * 2 + 1];

            float plat = deltay * distanceLat / (float)(18 * Math.Pow(2, zoom - 1));
            float plong = deltax * distanceLong / (float)(30 * Math.Pow(2, zoom - 1));
            plat += plat * 0.105f;

            float explat = centerLat - plat;
            float explong = centerLong + plong;

            Coordinate coor = new Coordinate(explat, explong);

            ServiceModel service = SearchBLL.GetNearPlaceCoordinate(coor);

            if (service == null) return Json(null);

            Tuple<IEnumerable<ServiceModel>, IEnumerable<PlaceModels>> Model =GetPlaceAround(service.Coordinate, type, r);

            return Json(new object[] { getViewContent(Model),
                service.Coordinate.Longitude,service.Coordinate.Latitude,service.Address });
        }

        private string getViewContent(Tuple<IEnumerable<ServiceModel>, IEnumerable<PlaceModels>> Model)
        {
            string str = "";
            if (Model == null || (Model.Item1 == null && Model.Item2 == null)
        || (Model.Item1 == null && Model.Item2.Count() == 0) || (Model.Item2 == null && Model.Item1.Count() == 0)
        || (Model.Item1.Count() == 0 && Model.Item2.Count() == 0))
            {
                str += "<li id='notfound'>Không tìm thấy kết quả</li>";
            }
            else
            {
                if (Model.Item1 != null)
                {
                    foreach (HCM_maps_website.Models.ServiceModel service in Model.Item1)
                    {
                        str += "<li>"
                            + "<h5>"+service.FullName+"</h5>"
                            + "<a class='address'>" + service.Address + "</a>"
                            + "<span class='function' datalat='" + service.Coordinate.Longitude + "' datalong='" + service.Coordinate.Latitude + "'>"
                                + "<a href='javascript:void(0)' class='viewmap'>Xem</a>"
                                + "<a href='javascript:void(0)' class='setstartpoint'>Điểm đi</a>"
                                + "<a href='javascript:void(0)' class='setendpoint'>Điểm đến</a>"
                                + "<a href='javascript:void(0)' class='findplacearound'>Xung quanh</a>"
                            + "</span>"
                        + "</li>";
                    }
                }
                if (Model.Item2 != null)
                {
                    foreach (HCM_maps_website.Models.PlaceModels place in Model.Item2)
                    {
                        str += "<li>"
                            + "<h5>" + place.Name + "</h5>"
                            + "<a class='address'>" + place.HomeNumber + " " + place.Area + "</a>"
                            + "<span class='function' datalat='" + place.Coordinate.Longitude + "' datalong='" + place.Coordinate.Latitude + "'>"
                                 + "<a href='javascript:void(0)' class='viewmap'>Xem</a>"
                                + "<a href='javascript:void(0)' class='setstartpoint'>Điểm đi</a>"
                                + "<a href='javascript:void(0)' class='setendpoint'>Điểm đến</a>"
                                + "<a href='javascript:void(0)' class='findplacearound'>Xung quanh</a>"
                            + "</span>"
                        + "</li>";
                    }
                }
            }

            return str;
        }

        [HttpPost]
        public ActionResult GetInfoFromCoordinate(int zoom, float plat , float plong)
        {        
            Coordinate coor = new Coordinate(plat, plong);

            ServiceModel service = SearchBLL.GetNearPlaceCoordinate(coor);



            return PartialView("_PlaceInfo", new ServiceModel[] { service });
        }

        [HttpPost]
        public ActionResult GetExactCoordinate(int zoom, int x, int y)
        {
            int deltax = x - centerXY[(zoom - 1) * 2];
            int deltay = y - centerXY[(zoom - 1) * 2 + 1];

            float plat = deltay *distanceLat / (float)(18 * Math.Pow(2, zoom - 1));
            float plong = deltax *distanceLong / (float)(30 * Math.Pow(2, zoom - 1));
            plat += plat * 0.105f;

            float explat = centerLat - plat;
            float explong = centerLong + plong;

            Coordinate coor = new Coordinate(explat, explong);

            ServiceModel place = SearchBLL.GetNearPlaceCoordinate(coor);

            //return Json(new object[] { coor.Longitude, coor.Latitude, place.Area }, JsonRequestBehavior.AllowGet);
            if (place != null)
                return Json(new object[] { place.Coordinate.Longitude, place.Coordinate.Latitude, place.Address }, JsonRequestBehavior.AllowGet);
            else return Json(null, JsonRequestBehavior.AllowGet);
        }

        private Tuple<IEnumerable<ServiceModel>, IEnumerable<PlaceModels>> GetPlaceAround(Coordinate coor, int type, int r)
        {
            IEnumerable<ServiceModel> services = null;
            if (type == -1)
            {
                services = serviceBL.FindServiceAround(coor, r);
            }
            else
            {
                services = serviceBL.FindServiceAroundWithServiceType(type, coor, r);
            }

            return new Tuple<IEnumerable<ServiceModel>, IEnumerable<PlaceModels>>(services, null);
        }

        
        [HttpPost]
        public ActionResult SaveRoute(double slat,double slong, double elat, double elong)
        {
            UserBLL userbll = new UserBLL();

            if (userbll.SaveSearchWay(((User)Session["Account"]).ID, slat,slong,elat,elong, DateTime.Now, DateTime.Now))
            {
                return Json("ok");
            }

            return Json("fail");
        }

        [HttpPost]
        public ActionResult SavePlace(int placeid)
        {
            UserBLL userbll = new UserBLL();

            if (userbll.SavePlace(((User)Session["Account"]).ID, placeid, DateTime.Now, DateTime.Now))
            {
                return Json("ok");
            }

            return Json("fail");
        }

        [HttpPost]
        public ActionResult GetUserRoute()
        {
            UserBLL userbll = new UserBLL();

            List<UserRoute> routes = userbll.ReturnUserRoute(((User)Session["Account"]).ID);
            List<RouteModels> lstroutes = new List<RouteModels>();
            foreach (UserRoute route in routes)
            {
                RouteModels mroute = new RouteModels()
                {
                    ID = route.ID,
                    UserID = route.UserID,
                    slat = route.xSource,
                    slong= route.ySource,
                    elat= route.xDestination,
                    elong = route.yDestination,
                    DateCreated = route.DateCreated,
                };
                try
                {
                    mroute.sPlace = SearchBLL.GetNearPlaceCoordinate(new Coordinate(route.xSource, route.ySource)).Address;
                    mroute.ePlace = SearchBLL.GetNearPlaceCoordinate(new Coordinate(route.xDestination, route.yDestination)).Address;
                }
                catch (Exception ex) { }

                lstroutes.Add(mroute);
            }
            return Json(lstroutes);
        }

        [HttpPost]
        public ActionResult GetUserPlace()
        {
            UserBLL userbll = new UserBLL();

            List<UserPlace> places = userbll.ReturnUserPlace(((User)Session["Account"]).ID);
            
            return PartialView("_UserPlace", places);
        }

        [HttpPost]
        public ActionResult Login(string username, string password)
        {
            if (Session["Account"] != null) return PartialView("_UserRef");

            UserBLL userbll = new UserBLL();
            
            var user = userbll.KTDangNhap(username.ToLower(), password);

            if (user != null)
            {
                Session["Account"] = user;

                return PartialView("_UserRef");
            }

            return PartialView("_Empty");
        }

        [HttpPost]
        public ActionResult Logout()
        {
                Session["Account"] = null;

            return Json("<a id='login' href='javascript:void(0)' onclick='ShowLogin();'>Đăng Nhập</a>");
        }

        [HttpPost]
        public ActionResult Register(string username,string password,string name,string email)
        {
            UserBLL userbll = new UserBLL();
            int id = userbll.AddUser(0, username, password, name, email);
            if (id>-1)
            {
                User user = new User() { ID = id, UserName = username, Password = password, Email = email, DisplayName = name };

                Session["Account"] = user;

                return PartialView("_UserRef");
            }

            return PartialView("_Empty");
        }
    }
}
